#ifndef BASEGRAPH_H_
#define BASEGRAPH_H_

#include "graph_support/Graph.h"
#include "graph_support/IGraph.h"

#include <vector>
#include <numeric>

#include <boost/bind.hpp>

#include "graph_support/exceptions/BadGraphItemException.h"
#include "graph_support/utils/ResolveTableT.h"

namespace GRAPH_SUPPORT_NS
{
namespace impls
{

template <
			typename VertexT,
			typename HashFn = stdext::hash< VertexT >,
			typename CmpFn = stdext::equal_to< VertexT >, // compares VertexT - s
			typename VertNumResolver = utils::ResolveTableHash< VertexT, size_t, HashFn, CmpFn >
			>
class BaseGraphTmpl : public Graph, public IGraph
{
public:
	typedef VertexT GrVertex;
	typedef typename std::vector< GrVertex >::iterator VertexIterator;

	template< typename IterT >
	BaseGraphTmpl( IterT verticesBeg, IterT verticesEnd, bool bidirected )
		: vertices( std::accumulate( verticesBeg, verticesEnd, 0, boost::bind( std::plus< int >(), _1, 1 ) ) )
		, isBidirected( bidirected )
	{
		init( verticesBeg, verticesEnd );
	}

	size_t getVertexCount() const
	{
		return vertices.size();
	}

	virtual size_t igetVertexCount() const
	{
		return getVertexCount();
	}

	VertexIterator getVerticesBeg()
	{
		return vertices.begin();
	}

	VertexIterator getVerticesEnd()
	{
		return vertices.end();
	}

	size_t vert2num( const GrVertex & v ) const
	{
		return Resolver::get( vert2numTable, v, ( const size_t ) NOT_A_VERTEX_ID );
	}

	const GrVertex num2vert( size_t vid ) const
	{
		return vertices[vid];
	}

private:
	typedef VertNumResolver Resolver;
	typedef typename Resolver::Table Vert2idTable;

	template< typename IterT >
	void init( IterT beg, IterT end )
	{
		Resolver::init( vert2numTable, beg, end );
		size_t i = 0;
		for ( IterT it = beg; it != end; ++it )
		{
			const GrVertex vert = * it;
			vertices[i] = vert;
			vert2numTable[vert] = i;
			i++;
		}
	}

protected:
	void checkVIDValid( size_t vid ) const
	{
		if ( vid >= vertices.size() )
		{
			throw GRAPH_SUPPORT_NS::exceptions::BadGraphItemException();
		}
	}

protected:
	typename std::vector< GrVertex > vertices;
	bool isBidirected;
	CmpFn areVerticesEqual;
	Vert2idTable vert2numTable;
};

}
}

#endif /* BASEGRAPH_H_ */
